<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
<meta name="viewport"
      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">

    <meta name="author" content="Ian Tang">


    <meta name="subtitle" content="岁月不居时节如流">


    <meta name="description" content="好记性不如烂笔头">



<title>c/c++语法使用 | 随笔</title>



    <link rel="icon" href="/image/The_Lion_King_32_32.png">




    <!-- stylesheets list from _config.yml -->
    
    <link rel="stylesheet" href="/css/style.css">
    



    <!-- scripts list from _config.yml -->
    
    <script src="/js/script.js"></script>
    
    <script src="/js/tocbot.min.js"></script>
    



    
    
        
    


<meta name="generator" content="Hexo 6.3.0"></head>

<body>
    <script>
        // this function is used to check current theme before page loaded.
        (() => {
            const currentTheme = window.localStorage && window.localStorage.getItem('theme') || '';
            const isDark = currentTheme === 'dark';
            const pagebody = document.getElementsByTagName('body')[0]
            if (isDark) {
                pagebody.classList.add('dark-theme');
                // mobile
                document.getElementById("mobile-toggle-theme").innerText = "· Dark"
            } else {
                pagebody.classList.remove('dark-theme');
                // mobile
                document.getElementById("mobile-toggle-theme").innerText = "· Light"
            }
        })();
    </script>

    <div class="wrapper">
        <header>
    <nav class="navbar">
        <div class="container">
            <div class="navbar-header header-logo"><a href="/">Tangkaifei&#39;s Blog</a></div>
            <div class="menu navbar-right">
                
                    <a class="menu-item" href="/archives">Posts</a>
                
                    <a class="menu-item" href="/category">Categories</a>
                
                    <a class="menu-item" href="/tag">Tags</a>
                
                    <a class="menu-item" href="/about">About</a>
                
                <input id="switch_default" type="checkbox" class="switch_default">
                <label for="switch_default" class="toggleBtn"></label>
            </div>
        </div>
    </nav>

    
    <nav class="navbar-mobile" id="nav-mobile">
        <div class="container">
            <div class="navbar-header">
                <div>
                    <a href="/">Tangkaifei&#39;s Blog</a><a id="mobile-toggle-theme">·&nbsp;Light</a>
                </div>
                <div class="menu-toggle" onclick="mobileBtn()">&#9776; Menu</div>
            </div>
            <div class="menu" id="mobile-menu">
                
                    <a class="menu-item" href="/archives">Posts</a>
                
                    <a class="menu-item" href="/category">Categories</a>
                
                    <a class="menu-item" href="/tag">Tags</a>
                
                    <a class="menu-item" href="/about">About</a>
                
            </div>
        </div>
    </nav>

</header>
<script>
    var mobileBtn = function f() {
        var toggleMenu = document.getElementsByClassName("menu-toggle")[0];
        var mobileMenu = document.getElementById("mobile-menu");
        if(toggleMenu.classList.contains("active")){
           toggleMenu.classList.remove("active")
            mobileMenu.classList.remove("active")
        }else{
            toggleMenu.classList.add("active")
            mobileMenu.classList.add("active")
        }
    }
</script>
            <div class="main">
                <div class="container">
    
    
        <div class="post-toc">
    <div class="tocbot-list">
    </div>
    <div class="tocbot-list-menu">
        <a class="tocbot-toc-expand" onclick="expand_toc()">Expand all</a>
        <a onclick="go_top()">Back to top</a>
        <a onclick="go_bottom()">Go to bottom</a>
    </div>
</div>

<script>
    var tocbot_timer;
    var DEPTH_MAX = 6; // 为 6 时展开所有
    var tocbot_default_config = {
        tocSelector: '.tocbot-list',
        contentSelector: '.post-content',
        headingSelector: 'h1, h2, h3, h4, h5',
        orderedList: false,
        scrollSmooth: true,
        onClick: extend_click,
    };

    function extend_click() {
        clearTimeout(tocbot_timer);
        tocbot_timer = setTimeout(function() {
            tocbot.refresh(obj_merge(tocbot_default_config, {
                hasInnerContainers: true
            }));
        }, 420); // 这个值是由 tocbot 源码里定义的 scrollSmoothDuration 得来的
    }

    document.ready(function() {
        tocbot.init(obj_merge(tocbot_default_config, {
            collapseDepth: 1
        }));
    });

    function expand_toc() {
        var b = document.querySelector('.tocbot-toc-expand');
        var expanded = b.getAttribute('data-expanded');
        expanded ? b.removeAttribute('data-expanded') : b.setAttribute('data-expanded', true);
        tocbot.refresh(obj_merge(tocbot_default_config, {
            collapseDepth: expanded ? 1 : DEPTH_MAX
        }));
        b.innerText = expanded ? 'Expand all' : 'Collapse all';
    }

    function go_top() {
        window.scrollTo(0, 0);
    }

    function go_bottom() {
        window.scrollTo(0, document.body.scrollHeight);
    }

    function obj_merge(target, source) {
        for (var item in source) {
            if (source.hasOwnProperty(item)) {
                target[item] = source[item];
            }
        }
        return target;
    }
</script>
    

    
    <article class="post-wrap">
        <header class="post-header">
            <h1 class="post-title">c/c++语法使用</h1>
            
                <div class="post-meta">
                    
                        Author: <a itemprop="author" rel="author" href="/">Ian Tang</a>
                    

                    
                        <span class="post-time">
                        Date: <a href="#">十一月 26, 2022&nbsp;&nbsp;9:56:00</a>
                        </span>
                    
                    
                        <span class="post-category">
                    Category:
                            
                                <a href="/categories/%E6%96%B9%E6%B3%95%EF%BC%9A%E6%96%B9%E6%B3%95%E8%AE%BA%EF%BC%88%E7%BB%8F%E9%AA%8C%E8%B0%88%EF%BC%89/">方法：方法论（经验谈）</a>
                            
                        </span>
                    
                </div>
            
        </header>

        <div class="post-content">
            <h3 id="const用法"><a href="#const用法" class="headerlink" title="const用法"></a>const用法</h3><h4 id="修饰函数"><a href="#修饰函数" class="headerlink" title="修饰函数"></a>修饰函数</h4><p>在普通的非 const成员函数中，this的类型是一个指向类类型的 const指针。可以改变this所指向的值，但不能改变 this所保存的地址。<br>在 const成员函数中，this的类型是一个指向 const类类型对象的 const指针。既不能改变 this所指向的对象，也不能改变 this所保存的地址。</p>
<h4 id="修饰函数的参数"><a href="#修饰函数的参数" class="headerlink" title="修饰函数的参数"></a>修饰函数的参数</h4><p>如果参数作输出用，不论它是什么数据类型，也不论它采用“指针传递”还是“引用传递”，都不能加const修饰，否则该参数将失去输出功能。const只能修饰输入参数。</p>
<p>如果输入参数采用“指针传递”，那么加const修饰可以防止意外地改动该指针，起到保护作用。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">例如StringCopy函数：</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">StringCopy</span> <span class="params">(<span class="type">char</span>*strDestination, <span class="type">const</span> <span class="type">char</span> *strSource)</span></span>;</span><br><span class="line">其中strSource是输入参数，strDestination是输出参数。给strSource加上<span class="type">const</span>修饰后，如果函数体内的语句试图改动strSource的内容，编译器将指出错误。</span><br></pre></td></tr></table></figure>

<p>如果输入参数采用“值传递”，由于函数将自动产生临时变量用于复制该参数，该输入参数本来就无需保护，所以不要加const修饰。</p>
<p>例如不要将函数void Func1(int x) 写成void Func1(const int x)。同理不要将函数void Func2(A a) 写成void Func2(const A a)。其中A为用户自定义的数据类型。</p>
<p>对于非内部数据类型的参数而言，象void Func(A a) 这样声明的函数注定效率比较底。因为函数体内将产生A类型的临时对象用于复制参数a，而临时对象的构造、复制、析构过程都将消耗时间。<br>为了提高效率，可以将函数声明改为void Func(A &amp;a)，因为“引用传递”仅借用一下参数的别名而已，不需要产生临时对象。但是函数void Func(A &amp;a) 存在一个缺点：<br>“引用传递”有可能改变参数a，这是我们不期望的。解决这个问题很容易，加const修饰即可，因此函数最终成为voidFunc(const A &amp;a)。<br>以此类推，是否应将void Func(int x) 改写为voidFunc(const int&amp;x)，以便提高效率？完全没有必要，因为内部数据类型的参数不存在构造、析构的过程，而复制也非常快，“值传递”和“引用传递”的效率几乎相当。</p>
<h5 id="summary"><a href="#summary" class="headerlink" title="summary"></a>summary</h5><p>对于非内部数据类型的输入参数，应该将“值传递”的方式改为“const引用传递”，目的是提高效率。例如将voidFunc(A a) 改为voidFunc(const A &amp;a)。<br>对于内部数据类型的输入参数，不要将“值传递”的方式改为“const引用传递”。否则既达不到提高效率的目的，又降低了函数的可理解性。例如voidFunc(int x) 不应该改为voidFunc(const int &amp;x)。</p>
<h4 id="修饰函数的返回值"><a href="#修饰函数的返回值" class="headerlink" title="修饰函数的返回值"></a>修饰函数的返回值</h4><p>如果给以“指针传递”方式的函数返回值加const修饰，那么函数返回值（即指针）的内容不能被修改，该返回值只能被赋给加const修饰的同类型指针。例如函数</p>
<p>const char * GetString(void);<br>如下语句将出现编译错误：<br>char *str &#x3D; GetString();<br>正确的用法是<br>const char  *str &#x3D;GetString();</p>
<p>如果函数返回值采用“值传递方式”，由于函数会把返回值复制到外部临时的存储单元中，加const修饰没有任何价值。<br>例如不要把函数int GetInt(void) 写成constint GetInt(void)。<br>同理不要把函数A GetA(void) 写成constA GetA(void)，其中A为用户自定义的数据类型。</p>
<p>如果返回值不是内部数据类型，将函数AGetA(void) 改写为constA &amp;GetA(void)的确能提高效率。但此时千万千万要小心，一定要搞清楚函数究竟是想返回一个对象的“拷贝”还是仅返回“别名”就可以了，否则程序会出错。<br>函数返回值采用“引用传递”的场合并不多，这种方式一般只出现在类的赋值函数中，目的是为了实现链式表达。</p>
<h4 id="const-成员函数"><a href="#const-成员函数" class="headerlink" title="const 成员函数"></a>const 成员函数</h4><p><strong>任何不会修改数据成员的函数都应该声明为const类型</strong>。如果在编写const成员函数时，不慎修改了数据成员，或者调用了其它非const成员函数，编译器将指出错误，这无疑会提高程序的健壮性。以下程序中，类stack的成员函数GetCount仅用于计数，从逻辑上讲GetCount应当为const函数。编译器将指出GetCount函数中的错误。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Stack</span></span><br><span class="line">&#123;</span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">Push</span><span class="params">(<span class="type">int</span> elem)</span></span>;</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">Pop</span><span class="params">(<span class="type">void</span>)</span></span>;</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">GetCount</span><span class="params">(<span class="type">void</span>)</span> <span class="type">const</span></span>; <span class="comment">// const 成员函数</span></span><br><span class="line"> <span class="keyword">private</span>:</span><br><span class="line">    <span class="type">int</span> m_num;</span><br><span class="line">    <span class="type">int</span> m_data[<span class="number">100</span>];</span><br><span class="line">&#125;;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">Stack::GetCount</span><span class="params">(<span class="type">void</span>)</span> <span class="type">const</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    ++ m_num; <span class="comment">// 编译错误，企图修改数据成员m_num</span></span><br><span class="line">    <span class="built_in">Pop</span>();<span class="comment">// 编译错误，企图调用非const函数</span></span><br><span class="line">    <span class="keyword">return</span>    m_num;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>const 成员函数的声明看起来怪怪的：const关键字只能放在函数声明的尾部，大概是因为其它地方都已经被占用了。<br>关于Const函数的几点规则：</p>
<blockquote>
<ul>
<li>const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数.</li>
<li>const对象的成员是不可修改的,然而const对象通过指针维护的对象却是可以修改的.</li>
<li>const成员函数不可以修改对象的数据,不管对象是否具有const性质.它在编译时,以是否修改成员数据为依据,进行检查.</li>
<li>然而加上mutable修饰符的数据成员,对于任何情况下通过任何手段都可修改,自然此时的const成员函数是可以修改它的</li>
</ul>
</blockquote>
<p>const放在后面跟前面有区别么<br>&#x3D;&#x3D;&gt;<br>准确的说const是修饰this指向的对象的<br>譬如，我们定义了</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">classA</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">f</span>(<span class="type">int</span>);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>这里f函数其实有两个参数，第一个是A<em>const this, 另一个才是int类型的参数<br>如果我们不想f函数改变参数的值，可以把函数原型改为f(const int),但如果我们不允许f改变this指向的对象呢？因为this是隐含参数，const没法直接修饰它，就加在函数的后面了，表示this的类型是const A <em>const this。<br>const修饰</em>this是本质，至于说“表示该成员函数不会修改类的数据。否则会编译报错”之类的说法只是一个现象，根源就是因为</em>this是const类型的</p>
<p>static const修饰：为了共享又不能修改。</p>
<p><a target="_blank" rel="noopener" href="https://cloud.tencent.com/developer/article/1637765">关于const和static的用法</a></p>
<h3 id="Template"><a href="#Template" class="headerlink" title="Template"></a>Template</h3><h4 id="类模板"><a href="#类模板" class="headerlink" title="类模板"></a>类模板</h4><p>template&lt; class 形参名，class 形参名，……&gt; class 类名 {…};</p>
<p><strong>template <class T> class A { public:  T a; T b;  T hy(T c, T &amp;d); };</strong></p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">class</span> <span class="title class_">T</span>&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">A</span>&#123;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">func</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function">T <span class="title">test</span><span class="params">(T&amp; a, T&amp; b)</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">class</span> <span class="title class_">T</span>&gt;</span><br><span class="line"><span class="type">void</span> A&lt;T&gt;::<span class="built_in">func</span>()&#123;    </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">class</span> <span class="title class_">T</span>&gt;</span><br><span class="line">T A&lt;T&gt;::<span class="built_in">test</span>(T a, T b)&#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="函数模板"><a href="#函数模板" class="headerlink" title="函数模板"></a>函数模板</h4><p><strong>函数模板提供了一种函数行为，该函数行为可以表示成多种类型进行调用，也就是说函数模板表时一个函数家族。</strong></p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">template</span>&lt;T&gt;</span></span><br><span class="line"><span class="function"><span class="keyword">inline</span> T <span class="type">const</span>&amp; <span class="title">Max</span><span class="params">(T <span class="type">const</span>&amp; a, T <span class="type">const</span>&amp; b)</span></span></span><br></pre></td></tr></table></figure>

<h5 id="这是有人会发出疑问？但我们实例化这个函数模板时，如果与非模板函数完全相同，那会不会产生二义性呢？"><a href="#这是有人会发出疑问？但我们实例化这个函数模板时，如果与非模板函数完全相同，那会不会产生二义性呢？" class="headerlink" title="这是有人会发出疑问？但我们实例化这个函数模板时，如果与非模板函数完全相同，那会不会产生二义性呢？"></a><strong>这是有人会发出疑问？但我们实例化这个函数模板时，如果与非模板函数完全相同，那会不会产生二义性呢？</strong></h5><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span>&#123;</span><br><span class="line">    <span class="type">int</span> a,b;</span><br><span class="line">    <span class="built_in">Max</span>&lt;<span class="type">int</span>&gt;(a, b);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="对于非模板函数和同名的模板函数，实例化后的模板函数如果与非模板函数完全相同，那么在调用的时候，编译器会默认为你调用的时非类型的。为什么呢？我是这样理解的：函数模板的实例化是需要花费时间和空间的，编译器肯定会选择时间与空间开支较少的。"><a href="#对于非模板函数和同名的模板函数，实例化后的模板函数如果与非模板函数完全相同，那么在调用的时候，编译器会默认为你调用的时非类型的。为什么呢？我是这样理解的：函数模板的实例化是需要花费时间和空间的，编译器肯定会选择时间与空间开支较少的。" class="headerlink" title="对于非模板函数和同名的模板函数，实例化后的模板函数如果与非模板函数完全相同，那么在调用的时候，编译器会默认为你调用的时非类型的。为什么呢？我是这样理解的：函数模板的实例化是需要花费时间和空间的，编译器肯定会选择时间与空间开支较少的。"></a>对于非模板函数和同名的模板函数，实例化后的模板函数如果与非模板函数完全相同，那么在调用的时候，编译器会默认为你调用的时非类型的。为什么呢？我是这样理解的：函数模板的实例化是需要花费时间和空间的，编译器肯定会选择时间与空间开支较少的。</h5><h3 id="函数指针-如何理解typedef-void-pfun-void"><a href="#函数指针-如何理解typedef-void-pfun-void" class="headerlink" title="函数指针-如何理解typedef void (*pfun)(void)"></a>函数指针-如何理解typedef void (*pfun)(void)</h3><h4 id="问题"><a href="#问题" class="headerlink" title="问题:"></a>问题:</h4><p>在刚接触typedef void (*pfun)(void) 这个结构的时候，存在疑惑，为什么typedef后只有一“块”东西，而不是两“块”东西呢？那是谁“替代”了谁啊？我总结了一下，一方面是对typedef的概念不清晰，另一方面受了#define的影响，犯了定向思维的错误。</p>
<h4 id="概念理解："><a href="#概念理解：" class="headerlink" title="概念理解："></a>概念理解：</h4><p>-typedef 只对已有的类型进行别名定义，不产生新的类型；</p>
<p>-# define只是在预处理过程对代码进行简单的替换。</p>
<p>清晰了解两个概念后，发现它们就是两个不同的概念，并没有太多的联系。</p>
<p><strong>类比理解：</strong></p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span>  <span class="type">unsigned</span> <span class="type">int</span>  UINT32;  <span class="comment">// UINT32 类型是unsigned int</span></span><br><span class="line">UINT32 sum;                     <span class="comment">// 定义一个变量：int sum;</span></span><br><span class="line"><span class="keyword">typedef</span>  <span class="type">int</span>  arr[<span class="number">3</span>];           <span class="comment">// arr 类型是 int[3];（存放int型数据的数组）</span></span><br><span class="line">arr a;                          <span class="comment">// 定义一个数组：int a[3];</span></span><br></pre></td></tr></table></figure>

<p>同理：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">typedef</span>  <span class="title">void</span> <span class="params">(*pfun)</span><span class="params">(<span class="type">void</span>)</span></span>;         <span class="comment">// pfun 类型是 void(*)(void)</span></span><br><span class="line">pfun main;                          <span class="comment">// 定义一个函数：void (*main)(void);</span></span><br></pre></td></tr></table></figure>

<p>在博客上看到一个经典的<a target="_blank" rel="noopener" href="http://www.cnblogs.com/shenlian/archive/2011/05/21/2053149.html">函数指针</a>用例：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="keyword">typedef</span> <span class="title">int</span> <span class="params">(*FP_CALC)</span><span class="params">(<span class="type">int</span>, <span class="type">int</span>)</span></span>;</span><br><span class="line"><span class="comment">//注意这里不是函数声明而是函数定义，它是一个地址，你可以直接输出add看看</span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">add</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">      <span class="keyword">return</span> a + b;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">sub</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">      <span class="keyword">return</span> a - b;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">mul</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> a * b;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">div</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">      <span class="keyword">return</span> b? a/b : <span class="number">-1</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//定义一个函数，参数为op，返回一个指针。该指针类型为 拥有两个int参数、</span></span><br><span class="line"><span class="comment">//返回类型为int 的函数指针。它的作用是根据操作符返回相应函数的地址</span></span><br><span class="line"><span class="function">FP_CALC <span class="title">calc_func</span><span class="params">(<span class="type">char</span> op)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">      <span class="keyword">switch</span> (op)</span><br><span class="line">      &#123;</span><br><span class="line">           <span class="keyword">case</span> <span class="string">&#x27;+&#x27;</span> : <span class="keyword">return</span> add;   <span class="comment">// 返回函数的地址</span></span><br><span class="line">           <span class="keyword">case</span> <span class="string">&#x27;-&#x27;</span> : <span class="keyword">return</span> sub;</span><br><span class="line">           <span class="keyword">case</span> <span class="string">&#x27;*&#x27;</span> : <span class="keyword">return</span> mul;</span><br><span class="line">           <span class="keyword">case</span> <span class="string">&#x27;/&#x27;</span> : <span class="keyword">return</span> div;</span><br><span class="line">           <span class="keyword">default</span>:</span><br><span class="line">	     <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//s_calc_func为函数，它的参数是 op，返回值为一个拥有两个int参数、返回类型为int 的函数指针</span></span><br><span class="line"><span class="built_in">int</span> (*<span class="built_in">s_calc_func</span>(<span class="type">char</span> op)) (<span class="type">int</span>, <span class="type">int</span>)</span><br><span class="line">&#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="built_in">calc_func</span>(op);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//最终用户直接调用的函数，该函数接收两个int整数，和一个算术运算符，返回两数的运算结果</span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">calc</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b, <span class="type">char</span> op)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	FP_CALC fp = <span class="built_in">calc_func</span>(op);       </span><br><span class="line">    <span class="comment">// 根据预算符得到各种运算的函数的地址</span></span><br><span class="line">     <span class="built_in">int</span> (*s_fp)(<span class="type">int</span>, <span class="type">int</span>) = <span class="built_in">s_calc_func</span>(op); </span><br><span class="line"><span class="comment">// 用于测试</span></span><br><span class="line"><span class="comment">// ASSERT(fp == s_fp);                          </span></span><br><span class="line"><span class="comment">// 可以断言这俩是相等的</span></span><br><span class="line">      <span class="keyword">if</span> (fp)&#123;</span><br><span class="line">          <span class="keyword">return</span> <span class="built_in">fp</span>(a, b);  <span class="comment">//根据上一步得到的函数的地址调用相应函数，并返回结果</span></span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">else</span>&#123;</span><br><span class="line">          <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">      &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">      <span class="type">int</span> a = <span class="number">100</span>, b = <span class="number">20</span>;</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;calc(%d, %d, %c) = %d\n&quot;</span>, a, b, <span class="string">&#x27;+&#x27;</span>, <span class="built_in">calc</span>(a, b, <span class="string">&#x27;+&#x27;</span>));</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;calc(%d, %d, %c) = %d\n&quot;</span>, a, b, <span class="string">&#x27;-&#x27;</span>, <span class="built_in">calc</span>(a, b, <span class="string">&#x27;-&#x27;</span>));</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;calc(%d, %d, %c) = %d\n&quot;</span>, a, b, <span class="string">&#x27;*&#x27;</span>, <span class="built_in">calc</span>(a, b, <span class="string">&#x27;*&#x27;</span>));</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;calc(%d, %d, %c) = %d\n&quot;</span>, a, b, <span class="string">&#x27;/&#x27;</span>, <span class="built_in">calc</span>(a, b, <span class="string">&#x27;/&#x27;</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>结合代码理解：</p>
<p>代码作者在注释中表述得很清楚，个人觉得最有意思就是一下这个函数：</p>
<p>FP_CALC calc_func(char op) &lt;–&gt; int (*calc_func(char op)) (int, int)</p>
<p>　　代码作者试图在断言中说明这个关系，相比较，还是FP_CALC calc_func(char op)函数更能表达编码者的意图：calc_func函数返回FP_CALC类型的指针，是一个函数指针，这个函数的形式是int (函数名)(int, int)，代码中int add(int a, int b)、int sub(int a, int b)…正是这样的格式。</p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/weixin_30840573/article/details/96461398">函数指针-如何理解typedef void (*pfun)(void)</a></p>
<h3 id="amp-引用"><a href="#amp-引用" class="headerlink" title="*&amp;*引用"></a>*&amp;*引用</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">double</span> vals[]=&#123;<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>&#125;;</span><br><span class="line"><span class="function"><span class="type">int</span>&amp; <span class="title">setvalue</span><span class="params">(<span class="type">int</span> i)</span></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> value[i];</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">setvalue</span>(<span class="number">2</span>) = <span class="number">30</span>; <span class="comment">//函数可以作为左值，因为返回的是一个引用，但是引用不能更改变量范围，例如本文引用的是数组vals的成员，是一个全局变量，如果是在函数内定义的局部变量，则需要用static修饰。</span></span><br></pre></td></tr></table></figure>

<p>判断是引用还是取地址，看是左值还是右值，<strong>左值是引用，右值是取地址</strong>。</p>
<h3 id="final"><a href="#final" class="headerlink" title="final"></a>final</h3><p>在类和函数后面：禁止继承和重载</p>
<h3 id="gt"><a href="#gt" class="headerlink" title="-&gt;"></a>-&gt;</h3><p>指向结构体的指针调用成员，或者指向类对象的指针调用成员函数或者父类函数</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">a</span> &#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">b</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br><span class="line">a *ptr;</span><br><span class="line">ptr-&gt;<span class="built_in">b</span>();</span><br><span class="line"><span class="comment">//-----------------------------------</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">b</span>&#123;</span><br><span class="line">    <span class="type">int</span> a ;</span><br><span class="line">&#125;</span><br><span class="line">b* ptr;</span><br><span class="line">ptr-&gt;a = <span class="number">0</span>;</span><br></pre></td></tr></table></figure>

<h3 id="extern"><a href="#extern" class="headerlink" title="extern"></a>extern</h3><p>extern可以不使用include导入相关的文件，就定义另一个文件的全局变量或者函数</p>
<h3 id="include"><a href="#include" class="headerlink" title="include"></a>include</h3><p>include导入头文件（**.h），相当于在编译的时候把头文件整个拷贝过来，头文件里只需要声明函数，不需要实现函数，函数体的实现在.c文件里，不需要include *.c文件。</p>
<h3 id="gdb调试"><a href="#gdb调试" class="headerlink" title="gdb调试"></a>gdb调试</h3><p>可以直接以调试模式执行程序</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gcc -o main main.c -g <span class="comment">//-g就是加入gdb模式</span></span><br></pre></td></tr></table></figure>

<p>或者找到正在运行的程序进行调试，前提就是程序编译时加入-g模式</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">找到进程pid</span></span><br><span class="line">ps -ef | grep xxx</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">进入进程内</span> </span><br><span class="line">gdb attach xxx</span><br><span class="line">(gdb) list #查看源码</span><br><span class="line">(gdb) r #运行run</span><br><span class="line">(gdb) b #加入断点 </span><br><span class="line">b pkt.c:22(在pkt.c文件的22行打断点) </span><br><span class="line">b eth_rcv （在函数eth_rcv入口打断点） </span><br><span class="line">info b；显示当前所有断点； </span><br><span class="line">d num；删除断点num； </span><br><span class="line">n num；向后执行num步</span><br><span class="line">clear n #清除断点</span><br><span class="line">(gdb) bt #查看函数调用栈的所有信息，当程序执行异常时，可通过此命令查看程序的调用过程；</span><br><span class="line">(gdb) c #继续执行</span><br><span class="line">(gdb) s #进入函数内部</span><br><span class="line">(gdb) n #下一步</span><br><span class="line">until：当你厌倦了在一个循环体内单步跟踪时，这个命令可以运行程序直到退出循环体；</span><br><span class="line">until+行号： 运行至某行，不仅仅用来跳出循环；</span><br><span class="line">finish： 运行程序，直到当前函数完成返回，并打印函数返回时的堆栈地址和返回值及参数值等信息；</span><br><span class="line">call 函数(参数)：调用程序中可见的函数，并传递“参数”，如：call gdb_test(55)；</span><br><span class="line">quit：简记为 q ，退出gdb；</span><br></pre></td></tr></table></figure>

<h3 id="指针-1"><a href="#指针-1" class="headerlink" title="指针+1"></a>指针+1</h3><p>指针 + 1 并不是指针代表的地址值 + 1.</p>
<p>指针变量加1，即向后移动1 个位置表示指针变量指向下一个数据元素的首地址。而不是在原地址基础上加1。至于真实的地址加了多少，要看原来指针指向的数据类型是什么。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">char</span> a = <span class="string">&#x27;a&#x27;</span>;</span><br><span class="line"><span class="type">char</span> *p = &amp;a;</span><br><span class="line"><span class="built_in">cout</span>&lt;&lt;(<span class="type">void</span>*)p&lt;&lt;<span class="string">&quot; &quot;</span>&lt;&lt;(<span class="type">void</span>*)(p+<span class="number">1</span>)&lt;&lt;<span class="built_in">endl</span>;</span><br><span class="line"><span class="comment">//输出：0012FF33  0012FF34</span></span><br></pre></td></tr></table></figure>

<p>p指向的是一个字符，p+1就是移动一个字符大小，一个字符就是一个字节，所以p +1 代表的地址就比 p 代表的地址大1。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> i = <span class="number">1</span>;</span><br><span class="line"><span class="type">int</span> *p = &amp;i;</span><br><span class="line"><span class="built_in">cout</span>&lt;&lt;(<span class="type">void</span>*)p&lt;&lt;<span class="string">&quot; &quot;</span>&lt;&lt;(<span class="type">void</span>*)(p+<span class="number">1</span>)&lt;&lt;<span class="built_in">endl</span>;</span><br><span class="line"><span class="comment">//输出：0012FF30  0012FF34</span></span><br></pre></td></tr></table></figure>

<p>p指向的是一个整型，p+1就是移动一个整型大小，即移动4个字节，所以p+1代表的地址比p代表的地址大4.0</p>
<h3 id="语句表达式-define"><a href="#语句表达式-define" class="headerlink" title="语句表达式 define"></a>语句表达式 define</h3><p><code>#define max(a,b) ( (a) &gt; (b) ? (a) : (b) )</code></p>
<ol>
<li>如果传递a++，b–，这种形式的参数，则会返回一个经过递增递减的值</li>
<li>不能确定a和b是同一种类型，不能使用comparison字符<strong>则使用typeof和指针类型比较两个变量</strong> <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&lt;include/linux/kernel.h&gt; </span><br><span class="line">#define max(a,b) \ </span><br><span class="line">       (&#123;typeof(a) _a = a;typeof(b) _b = b;</span><br><span class="line">	(void) (&amp;_a == &amp;_b);//如果两个类型不同，则指针类型不同，编译器这时候会报错，提升类型问题</span><br><span class="line">	_a &gt; _b ? (_a):(_b);</span><br><span class="line">	&#125;)</span><br></pre></td></tr></table></figure></li>
</ol>

        </div>

        
            <section class="post-copyright">
                
                    <p class="copyright-item">
                        <span>Author:</span>
                        <span>Ian Tang</span>
                    </p>
                
                
                    <p class="copyright-item">
                        <span>Permalink:</span>
                        <span><a href="https://tkhfree.github.io/2022/11/26/c_c++%E8%AF%AD%E6%B3%95%E4%BD%BF%E7%94%A8-2022-11-26/">https://tkhfree.github.io/2022/11/26/c_c++%E8%AF%AD%E6%B3%95%E4%BD%BF%E7%94%A8-2022-11-26/</a></span>
                    </p>
                
                
                    <p class="copyright-item">
                        <span>License:</span>
                        <span>Copyright (c) 2019 <a target="_blank" rel="noopener" href="http://creativecommons.org/licenses/by-nc/4.0/">CC-BY-NC-4.0</a> LICENSE</span>
                    </p>
                
                
                     <p class="copyright-item">
                         <span>Slogan:</span>
                         <span>Do you believe in <strong>DESTINY</strong>?</span>
                     </p>
                

            </section>
        
        <section class="post-tags">
            <div>
                <span>Tag(s):</span>
                <span class="tag">
                    
                    
                        <a href="/tags/c-c/"># c/c++</a>
                    
                        <a href="/tags/system/"># system</a>
                    
                        
                </span>
            </div>
            <div>
                <a href="javascript:window.history.back();">back</a>
                <span>· </span>
                <a href="/">home</a>
            </div>
        </section>
        <section class="post-nav">
            
                <a class="prev" rel="prev" href="/2022/11/27/Neutron%E5%AD%A6%E4%B9%A0-2022-11-27/">Neutron学习</a>
            
            
        </section>


    </article>
</div>

            </div>
            <footer id="footer" class="footer">
    <div class="copyright">
        <span>© Ian Tang | Powered by <a href="https://hexo.io" target="_blank">Hexo</a> & <a href="https://github.com/Siricee/hexo-theme-Chic" target="_blank">Chic</a></span>
    </div>
</footer>

    </div>
</body>

</html>